/**
 * Unsigned, immutable base-10 integer of arbitrary precision.  This class is implemented 
 * using a string to store the digits of the number. A final, static integer defines 
 * the base to be 10. 
 * 
 * @convention digits is a string, each character of which is a number 0-9.
 * @correspondence digits is represented in the abstract state by 'num'.
 * @author Sam Snyder
 * @see java.math.BigInteger
 */
public class SlowBigNatural implements BigNatural {

	/**
	 * This class is only built to deal with base-10 numbers. It would take slightly more
	 * refactoring than just changing the RADIX constant to get this class to work with 
	 * other bases, such as ensuring that 9+1=a, not 10, for bases higher than 10.
	 */
    private static final int RADIX = 10;
    
    /**
     * 	digits is where all of the data of a BigNatural is stored. Initially 0.
     */
    private final String digits;
    
    /**
     * Default constructor initializes digits to "0".
     * 
     */
    public SlowBigNatural() {
    	this.digits = "0";
    }

    /** 
     * int constructor initializes digits to an int. 
     * Presumes that the int is positive.
     * 
     * @param num int used to construct SlowBigNatural
     */
	public SlowBigNatural(int num) {
	    this.digits = Integer.toString(num);
	}

	/**
	 * String constructor initializes digits to a defensive copy of the given String. 
	 * Presumes good formatting on the part of said String, , such as that of 
	 * a string returned by Integer.toString()
	 * 
	 * @param num String used to construct SlowBigNatural
	 */
	public SlowBigNatural(String num) {
		this.digits = num;
	}

	/**
	 * BigNatural constructor uses the toString() method of a BigNatural to copy its value
	 * to this SlowBigNatural. 
	 * 
	 * @param num BigNatural used to construct SlowBigNatural
	 */
	public SlowBigNatural(BigNatural num) {
		this.digits = num.toString();
	}

	/**
	 * Returns the result of adding 1 to digits. Uses a ripple-carry technique.
	 * 
	 * @see BigNatural#increment()
	 */
	public BigNatural increment() {
		String result = this.digits;
		int index = result.length() - 1;
		boolean carry = true;
		while (carry && index >= 0) {
			int num = Character.digit(result.charAt(index), RADIX);
			String beforeindex = result.substring(0, index);
			String afterindex = "";
			// Preserve any this.digits which occur after the one currently being acted upon
			if (index + 1 < result.length()) {
				afterindex = result.substring(index + 1);
			}
			if (num != RADIX - 1) {
				carry = false;
			}
			num = (num + 1) % RADIX;
			// Replace the old digit with its new, incremented value
			result = beforeindex + Integer.toString(num) + afterindex;
			index--;  
		}
		// Add proceeding '1' if there is still a carry
		if (carry) {
			result = "1" + result;
		}
		return new SlowBigNatural(result);
	}

	/**
	 * Perform the subtraction of one from digits with a ripple-carry technique.
	 * "0" decremented remains "0".
	 * 
	 * @see BigNatural#decrement()
	 */
	public BigNatural decrement() {
		// If the number is already zero then do nothing, otherwise decrement
		String result = this.digits;
		if (!(result.length() == 1 && result.charAt(0) == '0')) {
			int index = result.length() - 1;
			boolean carry = true;
			while (carry && index >= 0) {
				int num = Character.digit(result.charAt(index), RADIX);
				String beforeindex = result.substring(0, index);
				String afterindex = "";
				// Preserve any this.digits which occur after the one currently being acted upon
				if (index + 1 < result.length()) {
					afterindex = result.substring(index + 1);
				}
				if (num != 0) {
					carry = false;
					num--;
				} else {
					num = RADIX - 1;
				}
				// Replace the old digit with its new, decremented value
				result = beforeindex + Integer.toString(num) + afterindex;
				index--;
			}
			// Remove proceeding '0' if the most significant 
			// bit was decremented from '1' to '0'
			if (result.charAt(0) == '0' && result.length() > 1) {
				result = result.substring(1, result.length());
			}
		}
		return new SlowBigNatural(result);
	}

	/**
	 * digits should already meet good-formatting requirements so return copy thereof. 
	 *  
	 * @see BigNatural#toString()
	 */
	public String toString() {
		return this.digits;
	}
}
